﻿/*
 * Vytvořeno aplikací SharpDevelop.
 * Uživatel: lebeda
 * Datum: 29.5.2012
 * Čas: 21:10
 *
 * Tento template můžete změnit pomocí Nástroje | Možnosti | Psaní kódu | Upravit standardní hlavičky souborů.
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using System.Diagnostics;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using ShellContextMenuHelper;
using SevenZip;

namespace locateGUI
{
    /// <summary>
    /// Description of MainForm.
    /// </summary>
    /// 
    
    using System.Configuration;
    
    
    public partial class MainForm : Form
    {
        private List<ResultSearchItem> resultItemList = new List<ResultSearchItem>();
        
        public CmdOptions options { get; set; }

        public MainForm()
        {
            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();

            //after the InitializeComponent() call
            searchTextBox.Tag = searchTextBox.Text;
            directoryTextBox.Tag = directoryTextBox.Text;
            
            resultListBox.Columns[0].Width = resultListBox.Width - 25;
            
            // statistics
            Lucene.Net.Store.Directory directory = LocateCommons.GetIndexDirectory();
            IndexReader reader = IndexReader.Open(directory, true);
            
            long indexDirSize = (GetDirectorySize(LocateCommons.indexDirName())) / 1024 /1024; // MB
            
            toolStripStatusLabel1.Text = "Index: " + reader.NumDocs().ToString("N0") + " items ("
                + indexDirSize.ToString("N0") + "MB)";
            
        }

        void findButtonClick(object sender, EventArgs e)
        {
            searchText();
        }

        public void doSearch(string text)
        {
            if (!String.IsNullOrEmpty(text)) {
                searchTextBox.Text = text;
                setComboBoxColor(searchTextBox);
                searchText();
            } else {
                searchTextBox.Text = (string)searchTextBox.Tag;
                setComboBoxColor(searchTextBox);
            }
        }

        public void setPath(string text)
        {
            if (!String.IsNullOrEmpty(text)) {
                //                directoryTextBox.
                directoryTextBox.Text = text;
                setComboBoxColor(directoryTextBox);
            } else {
                directoryTextBox.Text = (string)directoryTextBox.Tag;
                setComboBoxColor(directoryTextBox);
            }
        }
        
        void searchText()
        {
            // clear old search result
            resultListBox.Items.Clear();
            resultItemList.Clear();
            string querystr = searchTextBox.Text;
            toolStripStatusLabel1.Text = "";
            
            // normalize query string
            if (chNormalize.Checked) {
                querystr = LocateCommons.LatinToAscii(querystr);
                querystr = querystr.ToLower();
                querystr = "*"+querystr.Trim().Trim('*').Replace(' ','*')+"*";
                searchTextBox.Text = querystr;
            }

            // get path for query
            string queryPathStr = null;
            if (!directoryTextBox.Text.Equals(directoryTextBox.Tag)) {
                queryPathStr = directoryTextBox.Text;
            }

            // prepare and search new query
            Lucene.Net.Store.Directory directory = LocateCommons.GetIndexDirectory();
            IndexSearcher searcher = LocateCommons.getIndexSearcher(directory);
            int maxResult = Convert.ToInt32(ConfigurationManager.AppSettings.Get("maxResult"));
            maxResult = (maxResult == 0 ? 10000 : maxResult);
            ScoreDoc[] hits = LocateCommons.getSearchResult(querystr, queryPathStr, ref searcher, maxResult);

            // get result of new query and sort it
            List<ResultSearchItem> resultList = new List<ResultSearchItem>();
            int results = hits.Length;
            for (int i = 0; i < results; i++) {
                int docId = hits[i].Doc;
                float score = hits[i].Score;
                Document doc = searcher.Doc(docId);
                
                ResultSearchItem se = new ResultSearchItem(
                    doc.Get(LocateCommons.COL_TYPE),
                    doc.Get(LocateCommons.COL_KEY),
                    doc.Get(LocateCommons.COL_CONTENT),
                    doc.Get(LocateCommons.COL_TITLE),
                    score,
                    docId);
                
                resultList.Add(se);
                
            }
            // sort by type, score and key
            resultList.Sort(delegate(ResultSearchItem a, ResultSearchItem b)
                            {
                                int xdiff = a.Type.CompareTo(b.Type);
                                if (xdiff != 0) {
                                    return xdiff;
                                } else {
                                    string sortKeyA = normalizeForSort(a.Key);
                                    string sortKeyB = normalizeForSort(b.Key);
                                    xdiff = sortKeyA.CompareTo(sortKeyB);
                                    if (xdiff != 0) {
                                        return xdiff;
                                    } else {
                                        return a.Score.CompareTo(b.Score);
                                    }
                                }
                            });

            // fill new results into list
            string groupName = "";
            ListViewGroup group = null;
            foreach(ResultSearchItem resultItem in resultList) {
                // create new group on change
                if (!groupName.Equals(resultItem.Type)) {
                    group = new ListViewGroup(resultItem.Type);
                    resultListBox.Groups.Add(group);
                    groupName = resultItem.Type;
                }
                
                // check if file or archive exists
                bool fileExists = false;
                if (LocateCommons.isInArchive(resultItem.Key)) {
                    fileExists = File.Exists(LocateCommons.getArchivePath(resultItem.Key));
                } else if (LocateCommons.isNetworkPath(resultItem.Key)) {
                    fileExists = false;
                } else {
                    fileExists = File.Exists(resultItem.Key);
                }
                
                // add to result
                if (chVisible.Checked) {
                    if (fileExists) {
                        additem(resultItem, fileExists, group);
                    }
                } else {
                    additem(resultItem, fileExists, group);
                }
            }
            toolStripStatusLabel1.Text = "Found: " + resultListBox.Items.Count + " items";

            // set focus for user

            setFocus();
        }
        
        string normalizeForSort(string key)
        {
            string result = key;
            if (LocateCommons.isNetworkPath(key)) {
                result = "zzzz"+key;
            }
            return result;
        }

        void additem(ResultSearchItem resultItem, bool fileExists , ListViewGroup group)
        {
            ListViewItem lvi = new ListViewItem(resultItem.getItemTitle());
            
            if (LocateCommons.isNetworkPath(resultItem.Key)) {
                lvi.ForeColor = Color.DarkGreen;
            } else if (System.IO.Directory.Exists(resultItem.Key)) {
                lvi.ForeColor = Color.DarkBlue;
            } else if (!fileExists) {
                lvi.ForeColor = Color.Gray;
            }
            
            if (LocateCommons.isInArchive(resultItem.Key)) {
                lvi.Font = new Font(lvi.Font, FontStyle.Italic);
            }

            //            lvi.SubItems.Add(itemName+"a");
            //            lvi.SubItems.Add(itemName+"b");
//
            //            lvi.SubItems[2].ForeColor = Color.Blue;
//
            //            lvi.UseItemStyleForSubItems = false;
            
            lvi.Group = group;
            resultListBox.Items.Add(lvi);
            resultItemList.Add(resultItem);
        }
        
        void setFocus()
        {
            if (resultListBox.Items.Count > 0) {
                resultListBox.Focus();
            } else {
                searchTextBox.Focus();
                enterComboBox(searchTextBox);
            }
        }

        void ResultListBoxKeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar.Equals((char)System.Windows.Forms.Keys.Enter)) {
                // open selected file
                startFile(resultListBox.FocusedItem.Index);

            }
        }

        private void startFile(int itemIndex)
        {
            ResultSearchItem item = resultItemList[itemIndex];
            
            string fileName = item.Key;
            
            if (LocateCommons.isProtocolPath(fileName, ConfigurationManager.AppSettings.Get("netProtocols"))) {
                openProtocol(fileName);
            } else if (LocateCommons.isInArchive(fileName)) {
                string tempFile = createTempFileFromArchive(fileName);
                System.Diagnostics.Process.Start(tempFile);
                // TODO - delete all temp files
                
            } else if (File.Exists(fileName)) {
                System.Diagnostics.Process.Start(fileName);
            }
        }
        
        static long GetDirectorySize(string p)
        {
            // 1.
            // Get array of all file names.
            string[] a = Directory.GetFiles(p, "*.*");

            // 2.
            // Calculate total bytes of all files in a loop.
            long b = 0;
            foreach (string name in a)
            {
                // 3.
                // Use FileInfo to get length of each file.
                FileInfo info = new FileInfo(name);
                b += info.Length;
            }
            // 4.
            // Return total size
            return b;
        }
        
        void openProtocol(string url) {
            string protocol = LocateCommons.getProtocol(url).ToLower();
            
            string openCommandCmd = ConfigurationManager.AppSettings.Get("open_"+protocol+"_cmd");
            string openCommandArg = ConfigurationManager.AppSettings.Get("open_"+protocol+"_cmd");
            
            if (!String.IsNullOrWhiteSpace(openCommandCmd)) {
                openCommandArg = openCommandArg.Replace("%f", '"'+url+'"');
                
                Process p= new Process();
                p.StartInfo.FileName = openCommandCmd;
                p.StartInfo.Arguments = openCommandArg;
                p.Start();
            } else {
                System.Diagnostics.Process.Start(url);
            }
        }

        static string createTempFileFromArchive(string fileName)
        {
            // zip.Extracting += new EventHandler<ProgressEventArgs>(extr_Extracting);
            string archive = LocateCommons.getArchivePath(fileName);
            string file = LocateCommons.getArchiveInternalPath(fileName);
            string tempPath = System.IO.Path.GetTempPath();
            string tempFile = Path.Combine(tempPath, LocateCommons.getFileName(file));
            SevenZipExtractor zip = new SevenZipExtractor(archive);
            FileStream fs = new FileStream(tempFile, FileMode.Create);
            zip.ExtractFile(file, fs);
            fs.Close();
            return tempFile;
            // TODO - delete tempfile on exit...
        }
        
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            // Základní klávesové zkratky
            if (keyData == (Keys.Control | Keys.F)) {
                searchTextBox.Focus();
                return true;
            }

            if (keyData == (Keys.Control | Keys.L)) {
                resultListBox.Focus();
                return true;
            }

            if (keyData == (Keys.Control | Keys.P)) {
                Clipboard.SetText(resultListBox.FocusedItem.Text);
                return true;
            }

            // uživatelské klávesové zkratky
            if (keyData == Keys.F1) {
                runExternalCmd("F1");
            }
            if (keyData == Keys.F2) {
                runExternalCmd("F2");
            }
            if (keyData == Keys.F3) {
                runExternalCmd("F3");
            }
            if (keyData == Keys.F4) {
                runExternalCmd("F4");
            }
            if (keyData == Keys.F5) {
                runExternalCmd("F5");
            }
            if (keyData == Keys.F6) {
                runExternalCmd("F6");
            }
            if (keyData == Keys.F7) {
                runExternalCmd("F7");
            }
            if (keyData == Keys.F8) {
                runExternalCmd("F8");
            }
            if (keyData == Keys.F9) {
                runExternalCmd("F9");
            }
            if (keyData == Keys.F10) {
                runExternalCmd("F10");
            }
            if (keyData == Keys.F11) {
                runExternalCmd("F11");
            }
            if (keyData == Keys.F12) {
                runExternalCmd("F12");
            }

            // konec klávesových zkratek
            return base.ProcessCmdKey(ref msg, keyData);
        }
        
        void runExternalCmd(String keyCode) {
            int itemIndex = resultListBox.FocusedItem.Index;
            ResultSearchItem item = resultItemList[itemIndex];
            string filePath = item.Key;
            
            string cmd = "";
            string arg = "";
            string protocol = "";
            
            if (LocateCommons.isProtocolPath(filePath, ConfigurationManager.AppSettings.Get("netProtocols"))) {
                protocol = LocateCommons.getProtocol(filePath).ToLower();
                cmd = ConfigurationManager.AppSettings.Get(keyCode+"cmd_"+protocol);
                arg = ConfigurationManager.AppSettings.Get(keyCode+"arg_"+protocol);
            } else if (LocateCommons.isInArchive(filePath)) {
                cmd = ConfigurationManager.AppSettings.Get(keyCode+"cmdArch");
                arg = ConfigurationManager.AppSettings.Get(keyCode+"argArch");
            } else {
                cmd = ConfigurationManager.AppSettings.Get(keyCode+"cmd");
                arg = ConfigurationManager.AppSettings.Get(keyCode+"arg");
            }
            
            if (!String.IsNullOrEmpty(cmd + arg)) {
                arg = arg.Replace("%f", '"'+filePath+'"');
                arg = arg.Replace("%p", '"'+System.IO.Path.GetDirectoryName(filePath)+'"');
                
                arg = arg.Replace("%a", '"'+LocateCommons.getArchivePath(filePath)+'"');
                arg = arg.Replace("%i", '"'+LocateCommons.getArchiveInternalPath(filePath)+'"');
                
                if (arg.Contains("%t")) {
                    string tempFile = createTempFileFromArchive(filePath);
                    arg = arg.Replace("%t", '"'+tempFile+'"');
                }
                
                if (String.IsNullOrWhiteSpace(cmd)) {
                    System.Diagnostics.Process.Start(arg);
                } else {
                    Process p= new Process();
                    p.StartInfo.FileName = cmd;
                    p.StartInfo.Arguments = arg;
                    p.Start();
                }
            }
        }


        void SearchTextBoxKeyPress(object sender, KeyPressEventArgs e)
        {

            if (e.KeyChar.Equals((char)System.Windows.Forms.Keys.Enter)) {
                searchText();
            }
            //            else if ((searchTextBox.Text.Length > 5) && searchTextBox.Text.Contains("*")) {
            //                searchText();
            //            }


        }


        void SearchTextBoxEnter(object sender, EventArgs e)
        {
            TextBox txt = sender as TextBox;

            enterComboBox(txt);

        }

        void enterComboBox(TextBox txt)
        {
            if (txt.Text.Equals(txt.Tag as string)) {
                txt.Text = "";
            }
            txt.ForeColor = SystemColors.WindowText;
        }

        void SearchTextBoxLeave(object sender, EventArgs e)
        {
            TextBox txt = sender as TextBox;

            if (txt.Text.Trim().Equals("")) {
                txt.ForeColor = SystemColors.InactiveCaption;
                txt.Text = txt.Tag as string;
            }
        }

        void setComboBoxColor(TextBox textbox)
        {
            if (textbox.Text.Equals(textbox.Tag as string)) {
                textbox.ForeColor = SystemColors.InactiveCaption;
            } else {
                textbox.ForeColor = SystemColors.WindowText;
            }
        }

        void MainFormActivated(object sender, EventArgs e)
        {
            //            setComboBoxColor(searchTextBox);
            //            setComboBoxColor(directoryTextBox);

            //            setFocus();
        }


        void DirectoryButtonClick(object sender, EventArgs e)
        {
            if (!directoryTextBox.Text.Equals(directoryTextBox.Tag)) {
                folderBrowserDialog.SelectedPath = directoryTextBox.Text;
            }
            if (folderBrowserDialog.ShowDialog() ==  DialogResult.OK) {
                directoryTextBox.Text = folderBrowserDialog.SelectedPath;
                setComboBoxColor(directoryTextBox);
            }
        }
        
        
        void MainFormShown(object sender, EventArgs e)
        {
            chNormalize.Checked = options.normalize;
            chVisible.Checked = options.exists;
            
            setPath(options.pathToSearch);
            doSearch(options.phrase);
            
            setComboBoxColor(searchTextBox);
            setComboBoxColor(directoryTextBox);

            setFocus();
        }
        
        void ResultListBoxDoubleClick(object sender, EventArgs e)
        {
            startFile(resultListBox.FocusedItem.Index);
        }
        
        void ResultListBoxSizeChanged(object sender, EventArgs e)
        {
            resultListBox.Columns[0].Width = resultListBox.Width - 25;
        }
        
        
        void ResultListBoxMouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right) {
                if (File.Exists(resultListBox.FocusedItem.Text)) {
                    ShellContextMenu ctxMnu = new ShellContextMenu();
                    FileInfo[] arrFI = new FileInfo[1];
                    arrFI[0] = new FileInfo(resultListBox.FocusedItem.Text);
                    ctxMnu.ShowContextMenu(arrFI, this.PointToScreen(new Point(e.X, e.Y)));
                }
            }
        }
    }
}
